﻿using System;
using System.IO;
using System.Net;
using System.Text;

namespace WeiboSharp
{
    partial class Http
    {
        /// <summary>
        /// Execute a POST request
        /// </summary>
        public WeiboResponse Post()
        {
            return PostPutInternal("POST");
        }

        /// <summary>
        /// Execute a PUT request
        /// </summary>
        public WeiboResponse Put()
        {
            return PostPutInternal("PUT");
        }

        /// <summary>
        /// Execute a GET request
        /// </summary>
        public WeiboResponse Get()
        {
            return GetStyleMethodInternal("GET");
        }

        /// <summary>
        /// Execute a HEAD request
        /// </summary>
        public WeiboResponse Head()
        {
            return GetStyleMethodInternal("HEAD");
        }

        /// <summary>
        /// Execute an OPTIONS request
        /// </summary>
        public WeiboResponse Options()
        {
            return GetStyleMethodInternal("OPTIONS");
        }

        /// <summary>
        /// Execute a DELETE request
        /// </summary>
        public WeiboResponse Delete()
        {
            return GetStyleMethodInternal("DELETE");
        }

        private WeiboResponse GetStyleMethodInternal(string method)
        {
            var webRequest = ConfigureWebRequest(method, Url);

            return GetResponse(webRequest);
        }

        private WeiboResponse PostPutInternal(string method)
        {
            var webRequest = ConfigureWebRequest(method, Url);

            webRequest = PreparePostData(webRequest);

            webRequest = WriteRequestBody(webRequest);

            return GetResponse(webRequest);
        }

        private HttpWebRequest ConfigureWebRequest(string method, Uri url)
        {
            var webRequest = (HttpWebRequest)WebRequest.Create(url);
            webRequest.UseDefaultCredentials = false;
            ServicePointManager.Expect100Continue = false;

            webRequest = AppendHeaders(webRequest);

            webRequest.Method = method;

            // make sure Content-Length header is always sent since default is -1
            if (!HasFiles)
            {
                webRequest.ContentLength = 0;
            }

            webRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip | DecompressionMethods.None;

            if (!string.IsNullOrWhiteSpace(UserAgent))
            {
                webRequest.UserAgent = UserAgent;
            }

            if (Timeout != 0)
            {
                webRequest.Timeout = Timeout;
            }

            if (Credentials != null)
            {
                webRequest.Credentials = Credentials;
            }

            if (Proxy != null)
            {
                webRequest.Proxy = Proxy;
            }

            webRequest.AllowAutoRedirect = FollowRedirects;
            if (FollowRedirects && MaxRedirects.HasValue)
            {
                webRequest.MaximumAutomaticRedirections = MaxRedirects.Value;
            }

            return webRequest;
        }

        private WeiboResponse GetResponse(HttpWebRequest request)
        {
            var response = new WeiboResponse { StatusCode = HttpStatusCode.NotImplemented };

            try
            {
                var webResponse = GetRawResponse(request);
                response = ExtractResponseData(webResponse);
            }
            catch (Exception ex)
            {
                response.ErrorMessage = ex.Message;
                response.ErrorException = ex;
                response.StatusCode = HttpStatusCode.NotImplemented;
            }

            return response;
        }

        private HttpWebResponse GetRawResponse(HttpWebRequest request)
        {
            try
            {
                return (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                if (ex.Response is HttpWebResponse)
                {
                    return ex.Response as HttpWebResponse;
                }
                throw;
            }
        }

        private void WriteMultipartFormData(HttpWebRequest webRequest)
        {
            var encoding = Encoding.UTF8;
            using (Stream formDataStream = webRequest.GetRequestStream())
            {
                foreach (var param in Parameters)
                {
                    var postData = GetMultipartFormData(param);
                    var postBytes = encoding.GetBytes(postData);
                    formDataStream.Write(postBytes, 0, postBytes.Length);
                }
                foreach (var file in Files)
                {
                    // Add just the first part of this param, since we will write the file data directly to the Stream
                    string header = GetMultipartFileHeader(file);
                    var headerBytes = encoding.GetBytes(header);
                    formDataStream.Write(headerBytes, 0, headerBytes.Length);
                    // Write the file data directly to the Stream, rather than serializing it to a string.
                    file.Writer(formDataStream);
                    string lineEnding = Environment.NewLine;
                    formDataStream.Write(encoding.GetBytes(lineEnding), 0, lineEnding.Length);
                }
                string footer = GetMultipartFooter();
                formDataStream.Write(encoding.GetBytes(footer), 0, footer.Length);
            }
            //var encoding = Encoding.UTF8;
            //using (Stream formDataStream = webRequest.GetRequestStream())
            //{
            //    foreach (var param in Parameters)
            //    {
            //        var postData = GetMultipartFormData(param);
            //        var postBytes = encoding.GetBytes(postData);
            //        formDataStream.Write(postBytes, 0, postBytes.Length);
            //    }

            //    byte[] boundarybytes = encoding.GetBytes("\r\n--" + FormBoundary + "\r\n");
            //    formDataStream.Write(boundarybytes, 0, boundarybytes.Length);

            //    foreach (var file in Files)
            //    {
            //        // Add just the first part of this param, since we will write the file data directly to the Stream
            //        string header = GetMultipartFileHeader(file);
            //        var headerBytes = encoding.GetBytes(header);
            //        formDataStream.Write(headerBytes, 0, headerBytes.Length);
            //        // Write the file data directly to the Stream, rather than serializing it to a string.
            //        file.Writer(formDataStream);
            //        string lineEnding = Environment.NewLine;
            //        formDataStream.Write(encoding.GetBytes(lineEnding), 0, lineEnding.Length);
            //    }

            //    string footer = GetMultipartFooter();
            //    formDataStream.Write(encoding.GetBytes(footer), 0, footer.Length);
            //}
        }

        private HttpWebRequest WriteRequestBody(HttpWebRequest webRequest)
        {
            if (HasBody)
            {
                var encoding = Encoding.UTF8;
                var bytes = encoding.GetBytes(RequestBody);

                webRequest.ContentLength = bytes.Length;

                using (var requestStream = webRequest.GetRequestStream())
                {
                    requestStream.Write(bytes, 0, bytes.Length);
                }
            }
            return webRequest;
        }


        //    //同步方式发起http get请求
        //    public WeiboResponse HttpGet(string url, string queryString)
        //    {
        //        if (!string.IsNullOrEmpty(queryString))
        //        {
        //            url += "?" + queryString;
        //        }

        //        HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
        //        webRequest.Method = "GET";
        //        webRequest.ServicePoint.Expect100Continue = false;
        //        webRequest.Timeout = 20000;
        //        return ExtractResponseData(webRequest);
        //    }

        //    //同步方式发起http post请求
        //    public WeiboResponse HttpPost(string url, string queryString)
        //    {
        //        HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
        //        webRequest.Method = "POST";
        //        webRequest.ContentType = "application/x-www-form-urlencoded";
        //        webRequest.ServicePoint.Expect100Continue = false;
        //        webRequest.Timeout = 20000;

        //        using (var requestStream = webRequest.GetRequestStream())
        //        {
        //            using (var streatWriter = new StreamWriter(requestStream))
        //            {
        //                streatWriter.Write(queryString);
        //            }
        //        }
        //        return ExtractResponseData(webRequest);
        //    }

        //    //同步方式发起http post请求，可以同时上传文件
        //    public WeiboResponse HttpPostWithFile(string url, string queryString, List<FileParameter> files)
        //    {
        //        string boundary = DateTime.Now.Ticks.ToString("x");
        //        //url += "?" + queryString;
        //        HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
        //        webRequest.ServicePoint.Expect100Continue = false;
        //        webRequest.Timeout = 20000;
        //        webRequest.ContentType = "multipart/form-data; boundary=" + boundary;
        //        webRequest.Method = "POST";
        //        webRequest.KeepAlive = true;

        //        using (Stream memStream = new MemoryStream())
        //        {
        //            byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
        //            string formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";

        //            List<Parameter> listParams = Helper.GetQueryParameters(queryString);

        //            foreach (Parameter param in listParams)
        //            {
        //                string formitem = string.Format(formdataTemplate, param.Name, param.Value.DecodeFormParam());
        //                byte[] formitembytes = Encoding.UTF8.GetBytes(formitem);
        //                memStream.Write(formitembytes, 0, formitembytes.Length);
        //            }

        //            memStream.Write(boundarybytes, 0, boundarybytes.Length);

        //            var headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: \"{2}\"\r\n\r\n";

        //            foreach (FileParameter param in files)
        //            {
        //                string name = param.Name;
        //                string filePath = param.FileName;
        //                string file = Path.GetFileName(filePath);
        //                string contentType = file.GetFileType();
        //                string header = string.Format(headerTemplate, name, file, contentType);
        //                byte[] headerbytes = Encoding.UTF8.GetBytes(header);

        //                memStream.Write(headerbytes, 0, headerbytes.Length);
        //                using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        //                {
        //                    var buffer = new byte[1024];
        //                    int bytesRead;

        //                    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
        //                    {
        //                        memStream.Write(buffer, 0, bytesRead);
        //                    }

        //                    memStream.Write(boundarybytes, 0, boundarybytes.Length);
        //                }
        //            }

        //            webRequest.ContentLength = memStream.Length;
        //            using (Stream requestStream = webRequest.GetRequestStream())
        //            {
        //                memStream.Position = 0;
        //                var tempBuffer = new byte[memStream.Length];
        //                memStream.Read(tempBuffer, 0, tempBuffer.Length);

        //                requestStream.Write(tempBuffer, 0, tempBuffer.Length);
        //            }
        //        }
        //        return ExtractResponseData(webRequest);
        //    }
    }
}
